package ReflectStudy.Exa11;

import java.lang.reflect.*;

/**
 * 利用反射写出toString实现
 */
public class StringUtils {

    public static void main(String[] args) throws IllegalAccessException {
        Student student = new Student();
        student.setId(8);
        student.setAccount(20);
        student.setMale(true);
        student.setName("麻子");
        System.out.println(toString(student));
        System.out.println(toFieldString(student));
    }

    /**
     * 打印出对象obj中字段的值，实现思路：
     * 首先，我们要写出使用所有对象的toString方法，我们需要考虑以下几点，
     * 1.这个对象是否是普通对象，对于普通对象我们还要考虑里面的字段是否是基本类型或者引用类型，对于引用类型我们还需要对其进行递归获取打印操作
     * 2.这个对象是否是数组对象，对于数组对象，我们需要遍历里面的元素，在对其元素进行普通对象的操作
     * @param obj 对象
     * @return 字段值字符串
     * @throws IllegalAccessException
     */
    public static String toFieldString(Object obj) throws IllegalAccessException {
        //如果该对象为空直接返回
        if(obj==null) return null;
        Class<?> cl=obj.getClass();
        //如果该对象是字符串类型，直接返回之
        if(cl==String.class) return (String)obj;
        //如果该对象是数组对象，遍历之，并打印出各个元素对象中的字段值
        if(cl.isArray()){
            StringBuilder r= new StringBuilder(cl.getComponentType() + "[]{");
            for(int i=0;i< Array.getLength(obj);i++){
                if(i>0) r.append(" ");
                Object val=Array.get(obj,i);
                if(cl.getComponentType().isPrimitive())
                    r.append(val);
                else r.append(toFieldString(val));
            }
            return r+"}";
        }
        //如果是普通对象，遍历其中的字段打印之（包括父类的）
        StringBuilder r= new StringBuilder(cl.getName());
        do{
            r.append("[");
            //获得类的所有字段对象数组
            Field[] fields=cl.getDeclaredFields();
            //将字段数组设置为可操作的
            AccessibleObject.setAccessible(fields,true);
            //遍历字段数组
            for(Field field:fields){
                //如果该字段不是静态的，则对其进行是否基础类型的判断和下面的操作
                if(!Modifier.isStatic(field.getModifiers())){
                    if(!r.toString().endsWith("[")) r.append(",");
                    r.append(field.getName()).append("=");
                    Class<?> t= field.getType();
                    Object val= field.get(obj);
                    //t是不是基础类型
                    if(t.isPrimitive()) r.append(val);
                    else r.append(toFieldString(val));
                }else{
                    //否则就对静态字段的值进行打印
                    r.append(",");
                    r.append(field.getName()).append("=").append(field.get(obj));
                }
            }
            r.append("]");
            cl=cl.getSuperclass();
        }while (cl!=null);
        return r.toString();
    }

    /**
     * 只输出类的公共信息
     * @param object 对象
     * @return 该对象的类对象的公共信息
     */
    public static String toString(Object object) {
        // 获得代表该类的Class对象
        Class<?> clazz = object.getClass();
        // 利用StringBuilder来保存类信息
        StringBuilder strBuffer = new StringBuilder();
        // 获得类所在的包
        Package packageName = clazz.getPackage();
        // 输出类所在的包名
        strBuffer.append("包名：").append(packageName.getName()).append("\t");
        // 获得类的简单名称
        String className = clazz.getSimpleName();
        // 输出类的简单名称
        strBuffer.append("类名：").append(className).append("\n");
        strBuffer.append("公共构造方法：\n");
        // 获得所有构造方法的Constructor数组
        Constructor<?>[] constructors = clazz.getDeclaredConstructors();
        for (Constructor<?> constructor : constructors) {
            // 获得方法修饰符
            String modifier = Modifier.toString(constructor.getModifiers());
            // 查看修饰符是否含有“public”
            if (modifier.contains("public")) {
                //将此构造器的描述字符串输出
                strBuffer.append(constructor.toGenericString()).append("\n");
            }
        }

        strBuffer.append("公共域：\n");
        // 获得代表所有域的Field数组
        Field[] fields = clazz.getDeclaredFields();
        for (Field field : fields) {
            String modifier = Modifier.toString(field.getModifiers());
            // 查看修饰符是否含有“public”
            if (modifier.contains("public")) {
                strBuffer.append(field.toGenericString()).append("\n");
            }
        }

        strBuffer.append("公共方法：\n");
        // 获得代表所有方法的Method[]数组
        Method[] methods = clazz.getDeclaredMethods();
        for (Method method : methods) {
            String modifier = Modifier.toString(method.getModifiers());
            // 查看修饰符是否含有“public”
            if (modifier.contains("public")) {
                strBuffer.append(method.toGenericString()).append("\n");
            }
        }
        return strBuffer.toString();
    }





}
